package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"time"

	"github.com/spf13/cast"
	"github.com/spf13/viper"
	"gopkg.in/yaml.v3"
)

var ssUrl = "http://127.0.0.1:9500"

func GetAppToken(cfg *viper.Viper, tokenKey, appName string, sansanUrl ...string) (token string, err error) {
	if cfg == nil || len(tokenKey) == 0 {
		return
	}
	token = cfg.GetString(tokenKey)
	if len(token) > 0 {
		// 存在则直接返回
		return
	}
	if len(sansanUrl) > 0 && len(sansanUrl[0]) > 0 {
		// 支持指定ssurl
		ssUrl = sansanUrl[0]
	}
	// 先登录拿到接口token
	var tmp string
	if tmp, err = loginByInitAdmin(); err != nil {
		return
	}
	if len(tmp) == 0 {
		err = errors.New("登录三三失败")
		return
	}
	// 添加应用并得到永久token
	if token, err = addAppToken(tmp, appName); err != nil {
		return
	}
	// 保存token到配置文件
	cfg.Set(tokenKey, token)
	data, _ := yaml.Marshal(cfg.AllSettings())
	if err = ioutil.WriteFile(cfg.ConfigFileUsed(), data, os.ModePerm); err != nil {
		err = errors.New(fmt.Sprintf("write settings file error. %s", err.Error()))
	}
	return
}

func loginByInitAdmin() (tmp string, err error) {
	tsn := time.Now().UnixMilli()
	tss := strconv.FormatInt(tsn, 10)
	password, err := encodedPassword("123456aa", tsn)
	var resp map[string]interface{}
	if resp, err = sansanLogin("admin", password, tss); err != nil {
		return
	}
	if b, ok := resp["result"]; ok {
		if bMap, ok := b.(map[string]interface{}); ok {
			if c, ok := bMap["token"]; ok {
				tmp = cast.ToString(c)
			}
		}
	}
	return
}

func addAppToken(tk, appName string) (token string, err error) {
	param := make(map[string]interface{})
	param["appName"] = appName
	param["expireTime"] = time.Now().Add(99 * 365 * 24 * time.Hour).Format("2006-01-02 15:04:05")
	param["status"] = "1"
	param["mode"] = "all"
	header := make(map[string]string)
	header["Authentication"] = tk
	var resultJson interface{}
	err = HttpPostJson(ssUrl+"/api/user/app/add", param, header, &resultJson)
	if err != nil {
		err = errors.New("app接口异常" + err.Error())
		return
	}
	if resultJson == nil {
		err = errors.New("app接口异常,响应nil")
		return
	}
	resp := resultJson.(map[string]interface{})
	if resp["code"] == nil || resp["code"].(float64) != 200 {
		errMsg := If(resp["message"] != nil, resp["message"], "app token失败").(string)
		err = errors.New(errMsg)
		return
	}
	token = cast.ToString(cast.ToStringMap(resp["result"])["appToken"])
	return
}

func encodedPassword(password string, timestamp int64) (string, error) {
	// 生成密钥和IV
	key := fmt.Sprintf("aes%d", timestamp)
	// 创建AES加密块
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		err = errors.New("AES加密失败" + err.Error())
		return "", err
	}
	// 使用PKCS5Padding填充
	paddedPassword := pkcs5Padding([]byte(password), block.BlockSize())
	// 设置IV（与key相同）
	iv := []byte(key)
	// 创建CBC加密模式
	mode := cipher.NewCBCEncrypter(block, iv)
	// 加密
	ciphertext := make([]byte, len(paddedPassword))
	mode.CryptBlocks(ciphertext, paddedPassword)
	// Base64编码
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// PKCS5Padding 实现
func pkcs5Padding(src []byte, blockSize int) []byte {
	padding := blockSize - len(src)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padtext...)
}

func sansanLogin(username, password string, authtimestamp string) (resp map[string]interface{}, err error) {
	// 执行
	param := make(map[string]interface{})
	param["username"] = username
	param["password"] = password
	header := make(map[string]string)
	header["authtimestamp"] = authtimestamp
	var resultJson interface{}
	err = HttpPostJson(ssUrl+"/api/auth/login", param, header, &resultJson)
	if err != nil {
		err = errors.New("登录接口异常" + err.Error())
		return
	}
	if resultJson == nil {
		err = errors.New("登录接口异常,响应nil")
		return
	}
	resp = resultJson.(map[string]interface{})
	if resp["code"] == nil || resp["code"].(float64) != 200 {
		errMsg := If(resp["message"] != nil, resp["message"], "登录失败").(string)
		err = errors.New(errMsg)
		return
	}
	return
}
